/*******************************************
 * Copyright 2007 Aphrodite Framework for javaME .
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * Email : owner@aphroditeme.dev.java.net
 * Contributors:
 *     Kent Elton - initial API and implementation
 *******************************************/

package com.aphrodite.util.zip;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public final class ZipUtil {
	/**
	 * Do LZW compression on the given byte array
	 * 
	 * @param data
	 * @return
	 */
	public static byte[] doLZWCompress(byte[] data) throws IOException {
		ByteArrayInputStream bis = new ByteArrayInputStream(data);
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		final LZW lz = new LZW(bis, bos);
		lz.compress();
		return bos.toByteArray();

	}

	/**
	 * This function compresses a given byte array using the DEFLATE algorithm.
	 * 
	 * @param data
	 *            the input data to be compressed
	 * @return the resulting compressed byte array
	 * @throws IOException
	 */
	public static byte[] doZipCompress(byte[] data) throws IOException {
		return doZipCompress(data, ZipOutputStream.TYPE_DEFLATE);
	}

	/**
	 * This function compresses a given byte array using the DEFLATE algorithm.
	 * 
	 * @param data
	 *            the input data to be compressed
	 * @param compressionType
	 *            TYPE_GZIP or TYPE_DEFLATE
	 * @return the resulting compressed byte array
	 * @throws IOException
	 */
	public static byte[] doZipCompress(byte[] data, int compressionType) throws IOException {
		if (data.length > 1 << 15) {
			return doZipCompress(data, compressionType, 1 << 15, 1 << 15);

		} else {
			return doZipCompress(data, compressionType, data.length, data.length);

		}
	}

	/**
	 * This function compresses a given byte array using the DEFLATE algorithm.
	 * 
	 * @param data
	 *            the input data to be compressed
	 * @param compressionType
	 *            TYPE_GZIP or TYPE_DEFLATE
	 * @param plainWindowSize
	 *            this size is important for the lz77 search. Larger values will
	 *            result in better compression. Maximum is 32768.
	 * @param huffmanWindowSize
	 *            this size is important for the huffmanencoding. A large value
	 *            will result to a better frequency statistic and therefore to a
	 *            better compression.
	 * @return the resulting compressed byte array
	 * @throws IOException
	 */
	public static byte[] doZipCompress(byte[] data, int compressionType, int plainWindowSize, int huffmanWindowSize)
			throws IOException {
		ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
		ZipOutputStream zipOutputStream = new ZipOutputStream(bout, 1024, compressionType, plainWindowSize,
				huffmanWindowSize);

		zipOutputStream.write(data);
		zipOutputStream.close();

		return bout.toByteArray();
	}

	/**
	 * This function decompresses a given byte array using the DEFLATE
	 * algorithm.
	 * 
	 * @param data
	 *            the input data to be decompressed
	 * @return the resulting uncompressed byte array
	 * @throws IOException
	 */
	public static byte[] doZipDecompress(byte[] data) throws IOException {
		return doZipDecompress(data, ZipInputStream.TYPE_DEFLATE);
	}

	/**
	 * This function decompresses a given byte array using the DEFLATE or the
	 * GZIP algorithm.
	 * 
	 * @param data
	 *            the input data to be decompressed
	 * @param compressionType
	 *            TYPE_GZIP or TYPE_DEFLATE
	 * @return the resulting uncompressed byte array
	 * @throws IOException
	 */
	public static byte[] doZipDecompress(byte[] data, int compressionType) throws IOException {
		byte[] tmp = new byte[1024];
		int read;
		ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream(data), 1024, compressionType, true);
		ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
		// take from ZipInputStream and fill into ByteArrayOutputStream
		while ((read = zipInputStream.read(tmp, 0, 1024)) > 0) {
			bout.write(tmp, 0, read);
		}

		return bout.toByteArray();
	}

	private ZipUtil() {}
}
